﻿/*  
 * Helix Engine
 * http://helixengine.codeplex.com/
 * 
 * Copyright (c) 2010 - 2011 Joe Hegarty
 *  
 * This source code is subject to the terms of the Microsoft Public License (Ms-PL). 
 *  
 * Redistribution and use in source and binary forms, with or without modification, 
 * is permitted provided that redistributions of the source code retain the above 
 * copyright notices and this file header. 
 * 
 * For details please see http://www.opensource.org/licenses/ms-pl.html 
 *  
 * All other rights reserved. 
 *
 */  


using System;
using System.Net;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows;
using System.Windows.Resources;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Collections.Generic;

using HelixEngine.Render;

namespace HelixEngine.Resources
{
    /// <remarks>
    /// Represents a package of resources in ZIP format
    /// </remarks>
    public sealed class ResourcePackage
    {
        string _packageName;
        Uri _uri;
        StreamResourceInfo _streamResource;
        int _currentDownloadProgress;
        bool _complete = false;
        bool _error = false;
        WebClient _webClient = null;
        Dictionary<string, object> _cache;

        /// <summary>
        /// The name of the package
        /// </summary>
        public string PackageName
        {
            get
            {
                return _packageName;
            }
        }

        /// <summary>
        /// The progress of the download in percent
        /// </summary>
        public int DownloadProgress
        {
            get
            {
                return _currentDownloadProgress;
            }
        }

        /// <summary>
        /// Represents whether the package download is complete
        /// </summary>
        public bool IsComplete
        {
            get
            {
                return _complete;
            }
        }

        /// <summary>
        /// True when an error occured during down
        /// </summary>
        public bool IsError
        {
            get
            {
                return _error;
            }
        }

        /// <summary>
        /// Constructor for resource package, automatically requests the package
        /// </summary>
        /// <param name="packageName">The name of the package to request</param>
        public ResourcePackage(string packageName)
        {
            _packageName = packageName;
            _uri = new Uri("../assets/game/" + packageName + ".pak", UriKind.Relative);
            _webClient = new WebClient();
            _cache = new Dictionary<string, object>();
            FetchPackage();
        }


        //******************************************
        void FetchPackage()
        {
            _webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
            _webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OnOpenReadCompleted);
            _webClient.OpenReadAsync(_uri);
            _currentDownloadProgress = 0;
            _complete = false;
            _error = false;
        }

        //******************************************
        void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            _complete = true;
            try
            {
                _streamResource = new StreamResourceInfo(e.Result as Stream, null);
            }
            catch(Exception ex)
            {
                _error = true;
            }
        }

        //******************************************
        void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            _currentDownloadProgress = e.ProgressPercentage;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public WriteableBitmap GetBitmap(string path)
        {
            object result = null;
            if (!_cache.TryGetValue(path, out result))
            {
                StreamResourceInfo stream = null;
                if (_streamResource == null || !ResourceExists(path)) stream = Application.GetResourceStream(new Uri("HelixEngine;component/Resources/missing.png", UriKind.Relative));
                if (stream == null) stream = Application.GetResourceStream(_streamResource, new Uri(path, UriKind.Relative));
                BitmapImage bitmap = new BitmapImage();
                bitmap.SetSource(stream.Stream);
                result = new WriteableBitmap(bitmap);
                _cache.Add(path, result);
            }
            
            return (WriteableBitmap) result;
        }

        /// <summary>
        /// Get's a text file from the package
        /// </summary>
        /// <param name="path">Path in the package to the text file needed</param>
        /// <returns>string containing the contents of the requested file</returns>
        public string GetText(string path)
        {
            object result = null;
            if (!_cache.TryGetValue(path, out result))
            {
                if (_streamResource == null || !ResourceExists(path)) return "UNDEFINED";
                StreamResourceInfo stream = Application.GetResourceStream(_streamResource, new Uri(path, UriKind.Relative));
                TextReader reader = new StreamReader(stream.Stream);
                result = reader.ReadToEnd();
                _cache.Add(path, result);
            }

            return (string) result;
        }


        /// <summary>
        /// Checks whether an asset exists in the package
        /// </summary>
        /// <param name="path">The path to check exists</param>
        /// <returns>True when the  resource exists6</returns>
        public bool ResourceExists(string path)
        {
            if (_cache.ContainsKey(path)) return true;
            StreamResourceInfo stream = Application.GetResourceStream(_streamResource, new Uri(path, UriKind.Relative));
            return stream != null;
        }
    }
}
